#include "OurCallbackObject.h"
#include "vr.h"
#include "OurModel.h"
#include "OurObject.h"
#include <iostream>
using std::cout;
using std::endl;

#define max(a,b) (((a) > (b)) ? (a) : (b)) 
#define min(a,b) (((a) < (b)) ? (a) : (b)) 

OurCallbackObject::OurCallbackObject (OurModel *model) :
	m_model(model)
{
}

void OurCallbackObject::PreTraverseNode (VRNode * node) {
	
	//cout<<"node->type == "<<node->type<<endl;
	if (node->type != VR_COORDINATE)
		return;

	// so we know node type is VR_COORDINATE.



	//parse all coordinates in a coordiante list of a single object
	VRCoordinate* coords = (VRCoordinate*)(node);
	OurObject* pNewObject = m_model->createObject();
	for(unsigned int i=0;i<coords->point.numValues;i++)
	{
		pNewObject->AddPoint(coords->point.values[i][0],
							 coords->point.values[i][1],
							 coords->point.values[i][2]);

		m_model->m_dbSumXcoord += coords->point.values[i][0];
		m_model->m_dbSumYcoord += coords->point.values[i][1];
		m_model->m_dbSumZcoord += coords->point.values[i][2];
		m_model->m_nNumOfPoints ++;
		
		if(m_model->IsChanged()==false)
		{
			m_model->SetChanged(true);
			m_model->m_dbMaxXcoord = coords->point.values[i][0];
			m_model->m_dbMaxYcoord = coords->point.values[i][1];
			m_model->m_dbMaxZcoord = coords->point.values[i][2];
			m_model->m_dbMinXcoord = coords->point.values[i][0];
			m_model->m_dbMinYcoord = coords->point.values[i][1];
			m_model->m_dbMinZcoord = coords->point.values[i][2];	
		}
		m_model->m_dbMaxXcoord = max(coords->point.values[i][0],m_model->m_dbMaxXcoord);
		m_model->m_dbMaxYcoord = max(coords->point.values[i][1],m_model->m_dbMaxYcoord);
		m_model->m_dbMaxZcoord = max(coords->point.values[i][2],m_model->m_dbMaxZcoord);
		m_model->m_dbMinXcoord = min(coords->point.values[i][0],m_model->m_dbMinXcoord);
		m_model->m_dbMinYcoord = min(coords->point.values[i][1],m_model->m_dbMinYcoord);
		m_model->m_dbMinZcoord = min(coords->point.values[i][2],m_model->m_dbMinZcoord);	
	}

	//parse the coordIndex from the parent
	VRIndexedFaceSet* vrIndexFaceSet  = (VRIndexedFaceSet*)(node->parent);
	
	//parse the index array, each primitive is terminated by -1
	for(unsigned int i=0;i<vrIndexFaceSet->coordIndex.numValues;i++)
	{
		//parse the indexes of a single primitive;
		vector<unsigned> FacesIndex;
		for(unsigned int j=i;j<vrIndexFaceSet->coordIndex.numValues;j++)
		{
			if(vrIndexFaceSet->coordIndex.values[j] == -1)
			{
				i=j;
				break;
			}
			//cout<<vrIndexFaceSet->coordIndex.values[j];
			FacesIndex.push_back(vrIndexFaceSet->coordIndex.values[j]);

		}

		cout<<"AddFace = "<<pNewObject->AddFace(FacesIndex)<<endl;
	}

	// let's see if we can load face normals from vrml:         
	if(vrIndexFaceSet->normalPerVertex == false && vrIndexFaceSet->normal && vrIndexFaceSet->normal->vector.numValues > 0) {
		VRMFInt32 &index = (vrIndexFaceSet->normalIndex.numValues == 0)? vrIndexFaceSet->coordIndex : vrIndexFaceSet->normalIndex;                 
		for (unsigned int j = 0; j < index.numValues; j++) {                        
			int idx_normal = index.values[j];                        
			int idx_face = vrIndexFaceSet->coordIndex.values[j];
			if (idx_normal < 0 || idx_face < 0)
				continue;

			pNewObject->ModifyFaceNormal(idx_face, vrIndexFaceSet->normal->vector.values[idx_normal][0], 
				vrIndexFaceSet->normal->vector.values[idx_normal][1], vrIndexFaceSet->normal->vector.values[idx_normal][2]);
		}
	}

	// let's add vertex normals: (some strange code)          
	if(vrIndexFaceSet->normalPerVertex && vrIndexFaceSet->normal && vrIndexFaceSet->normal->vector.numValues > 0) {
		VRMFInt32 &index = (vrIndexFaceSet->normalIndex.numValues == 0)? vrIndexFaceSet->coordIndex : vrIndexFaceSet->normalIndex;                 
		for (unsigned int j = 0; j < index.numValues; j++) {                        
			int idx_normal = index.values[j];                        
			int idx_point = vrIndexFaceSet->coordIndex.values[j];
			if (idx_normal < 0 || idx_point < 0)
				continue;

			pNewObject->AddVertexNormal(idx_point, vrIndexFaceSet->normal->vector.values[idx_normal][0], 
				vrIndexFaceSet->normal->vector.values[idx_normal][1], vrIndexFaceSet->normal->vector.values[idx_normal][2]);
		}
	}
	else
	{
		//calculate the normals by ourselves
		pNewObject->CalculateVertexNormals();
	}

	//now we parse the color attributes of this shape
	VRShape* ParentShape = (VRShape*)vrIndexFaceSet->parent;
	
	vector<int> Kd;
	vector<int> Ks;
	vector<int> Ka;
	
	double AmbientIntensity = 
		ParentShape->appearance->material->ambientIntensity;

	for(unsigned i=0;i<3;i++)
	{
		Kd.push_back(
			static_cast<int>(
			ParentShape->appearance->material->diffuseColor[i]*255));
	}
	for(unsigned i=0;i<3;i++)
	{
		Ks.push_back(
			static_cast<int>(
			ParentShape->appearance->material->specularColor[i]*255));
	}
	

	int n = ParentShape->appearance->material->shininess*128;

	/*if(vrIndexFaceSet->colorPerVertex == true && 
	   vrIndexFaceSet->coordIndex.numValues > 0)
	{
		for(unsigned i=0;i<3;i++)
		{
			Kd[i] = vrIndexFaceSet->coordIndex.values[0];
		}
	}*/

	for(unsigned i=0;i<3;i++)
	{
		Ka.push_back(
			static_cast<int>(Kd[i]*AmbientIntensity));
	}
	
	pNewObject->SetKa(Ka);
	pNewObject->SetKd(Kd);
	pNewObject->SetKs(Ks);
	pNewObject->SetN(n);
	pNewObject->SetAmbientIntensity(AmbientIntensity);

	if(vrIndexFaceSet->colorPerVertex == true && 
	   vrIndexFaceSet->color &&
	   vrIndexFaceSet->color->color.numValues >0)
	{
		pNewObject->ColorPerVertex(true);

		VRMFInt32 &index = (vrIndexFaceSet->colorIndex.numValues == 0)? 
						   vrIndexFaceSet->coordIndex : vrIndexFaceSet->colorIndex;                 
		for (unsigned int j = 0; j < index.numValues; j++) {                        
			
			
			int idx_color = index.values[0];                        
			int idx_point = vrIndexFaceSet->coordIndex.values[j];
			if (idx_color < 0 || idx_point < 0)
				continue;
			
			pNewObject->SetVertexColor(idx_point,
				255*vrIndexFaceSet->color->color.values[idx_color][0],
				255*vrIndexFaceSet->color->color.values[idx_color][1],
				255*vrIndexFaceSet->color->color.values[idx_color][2]);
		}
	}
	else if(vrIndexFaceSet->colorPerVertex == false && 
			vrIndexFaceSet->color &&
			vrIndexFaceSet->color->color.numValues >0)
	{
		pNewObject->ColorPerFace(true);
		
		VRMFInt32 &index = (vrIndexFaceSet->colorIndex.numValues == 0)? 
			vrIndexFaceSet->coordIndex : vrIndexFaceSet->colorIndex;                 
		for (unsigned int j = 0; j < index.numValues; j++) 
		{                        
			int idx_color = index.values[j];                        
			//int idx_face = vrIndexFaceSet->coordIndex.values[j];
			if (idx_color < 0)
				continue;
			pNewObject->SetFaceColor(j,
				255*vrIndexFaceSet->color->color.values[idx_color][0],
				255*vrIndexFaceSet->color->color.values[idx_color][1],
				255*vrIndexFaceSet->color->color.values[idx_color][2]);
		}
	}
	//pNewObject->AddTriangulates();	
}
void OurCallbackObject::PostTraverseNode(VRNode * node)
{
}
